/*
  FtpServer.java
*/

import java.io.*;
import java.util.*;
import java.net.*;

public class FtpServer
{
  static int connCount = 1;

  //===================================================

  public static void main(String arg[])
  {
    FtpServer server = new FtpServer();
    while(true)
    {
      try
      {
        Thread.sleep(1000);
      }
      catch(InterruptedException e)
      {
        System.out.printf("%s\n", e);
      }
    }
  }

  //====================================================

  public FtpServer()
  {
    try
    {
      // 8000 allows server & client on same machine
      ServerSocket sv = new ServerSocket(8000);
      while (true)
      {	
        if(connCount == 1)
          System.out.println("Server:\t\tWaiting for client to connect...");
        Socket connSK=sv.accept();
        System.out.println("Server:\t\tA client's request for FTP connection accepted...");
        ThreadedConnectionHandler t = new ThreadedConnectionHandler(connSK, connCount);
        t.start();
        connCount++;
        System.out.println("Server:\t\tWaiting for other client connections...");
      }
    }
    catch(Exception e) 
    { 
      System.out.println(e.toString()); 
    }

  }

  //===================================================

  public class ThreadedConnectionHandler extends Thread
  {
    private Socket sk = null;
    private boolean stop = false;
    private int curConnect = 0;
    private String str = null;
    private CmdFiles cmds = new CmdFiles(".");
    private FtpCommon.Mode mode = FtpCommon.Mode.Binary;
    private FtpCommon.Command command = FtpCommon.Command.Ls;

    //===================================================

    public ThreadedConnectionHandler(Socket s, int k)
    {
      sk = s;  
      curConnect = k;
      System.out.println("Session " + k + ":\tconnection established.");
    }

    //===================================================

    public void run()
    {	
      try
      {	
        BufferedReader in = new BufferedReader(new InputStreamReader(sk.getInputStream()));
        PrintWriter out = new PrintWriter(sk.getOutputStream(), true);
        System.out.println("Session " + curConnect + ":\tSending FTP Welcome message...");
        out.println("MESSAGE:\t\t\t===========================\r");
        out.println("MESSAGE:\t\t\tWelcome to FTP Test Program\r");
        out.println("MESSAGE:\t\t\t===========================\r");
        System.out.println("Session " + curConnect + ":\t...waiting for commands");

        FtpCommon.sendCommand("ServerReady", sk);

        while(!stop)
        {
          String com = getCommand(in, out);

          if(com == null)
          {
            stop = true;
            break;
          } 

          if(com.startsWith("MESSAGE:"))
          {
            com = com.substring(8);
            System.out.printf("Session " + curConnect + ": recieved message: %s\n", com);
            FtpCommon.sendCommand("ServerReady", sk);
          }
          else if(com.startsWith("COMMAND:"))
          {
            com = com.substring(8);
            if(!com.equals("ClientReady"))
              System.out.printf("Session " + curConnect + ": recieved command: %s\n", com);
            LinkedList<String> cmd = FtpCommon.tokenizeString(com);
            processCommand(cmd);
          }
          else
            System.out.printf("(*ERROR*): unrecognized response: %s\n", com);
        }

        System.out.println("Session " + curConnect + ":\tconnection closed.");
      }
      catch(IOException e)
      { 
        System.out.printf("%s\n", e);
      }
      finally
      {
        try
        {
          sk.close();
        }
        catch(IOException e)
        { 
          System.out.printf("%s\n", e);
        }
      }
    }
    

    //===================================================

    boolean processCommand(LinkedList<String> cmd)
    {
      if(cmd.get(0).equals("ClientReady"))
      {
        FtpCommon.sendCommand("ServerReady", sk);
        return true;
      }
      else if(cmd.get(0).equals("bin"))
      {
        mode = FtpCommon.Mode.Binary;
        System.out.printf("Session "+curConnect+": Setting mode to binary\n");
        FtpCommon.sendCommand("bin", sk);
      }
      else if(cmd.get(0).equals("ascii"))
      {
        mode = FtpCommon.Mode.Ascii;
        System.out.printf("Session "+curConnect+": Setting mode to ascii\n");
        FtpCommon.sendCommand("ascii", sk);
      }
      else if(cmd.get(0).equals("ls"))
      {
        File temp = new File(cmds.getDir());
        command = FtpCommon.Command.Ls;
        cmds.listDirectory();
        FtpCommon.sendCommand("ls"+temp.getAbsolutePath(), sk);
      }
      else if(cmd.get(0).equals("pwd"))
      {
        File temp = new File(cmds.getDir());
        FtpCommon.sendCommand("pwd"+temp.getAbsolutePath(), sk);
      }
      else if(cmd.get(0).equals("cd"))
      {
        if(cmd.size() > 1)
        {
          File temp = new File(cmds.getDir());
          String dir = cmd.get(1).toString().trim();
          cmds.cdRelative(cmd.get(1).toString().trim());
        }
        else
          cmds.cdAbsolute("/");
      }
      else
        return false;
      
      FtpCommon.sendCommand("ServerReady", sk);
      return true;
    }

    //===================================================

    public String getCommand(BufferedReader in, PrintWriter out)
    {		
      str = null;
      try
      {
        str = in.readLine();
      }
      catch (Exception e)
      {
        out.println("Error reading input.");
      }
      return str;
    }
  }
}
